#include "D3D10RenderDevice.h"
#include "Utility/Utility.h"
#include "VertexBuffer.h"
#include "IndexBuffer.h"


#ifndef _WIN32_WINNT
#define _WIN32_WINNT   0x0600 // Vista
#endif

#if defined(DEBUG) || defined(_DEBUG)
#ifndef D3D_DEBUG_INFO
#define D3D_DEBUG_INFO
#endif
#endif

#if defined(DEBUG) || defined(_DEBUG)
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#endif


static const D3DXCOLOR CLEAR_COLOR = D3DXCOLOR(0.5f, 0.5f, 0.5f, 1.0f);


CD3D10RenderDevice::CD3D10RenderDevice()
	: m_pDevice(0)
	, m_pSwapChain(0)
	, m_pDepthStecilBuffer(0)
	, m_pRenderTargetView(0)
	, m_pDepthStencilView(0)
	, m_pFont(0)
	, m_eD3DDriverType(D3D10_DRIVER_TYPE_HARDWARE)
	, m_nViewWidth(0)
	, m_nViewHeight(0)
{

}

CD3D10RenderDevice::~CD3D10RenderDevice()
{
	UnInit();
}

bool CD3D10RenderDevice::Init( HWND hMainWnd, int nViewWidth, int nViewHeight )
{
	DXGI_SWAP_CHAIN_DESC  desc;
	desc.BufferDesc.Width  = nViewWidth;
	desc.BufferDesc.Height = nViewHeight;
	desc.BufferDesc.RefreshRate.Numerator = 60;
	desc.BufferDesc.RefreshRate.Denominator = 1;
	desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
	desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
	desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;

	desc.SampleDesc.Count = 1;
	desc.SampleDesc.Quality = 0;

	desc.BufferUsage  = DXGI_USAGE_RENDER_TARGET_OUTPUT;
	desc.BufferCount  = 1;
	desc.OutputWindow = hMainWnd;
	desc.Windowed     = true;
	desc.SwapEffect   = DXGI_SWAP_EFFECT_DISCARD;
	desc.Flags        = 0;

	UINT  dwCreateDeviceFlags = 0;

#if defined(DEBUG) || defined(_DEBUG)
	//dwCreateDeviceFlags |= D3D10_CREATE_DEVICE_DEBUG;
#endif
	
	HR(D3D10CreateDeviceAndSwapChain(
		0, 
		m_eD3DDriverType,
		0,
		dwCreateDeviceFlags,
		D3D10_SDK_VERSION,		
		&desc,
		&m_pSwapChain,
		&m_pDevice));


	// Create Font
	D3DX10_FONT_DESC fontDesc;
	fontDesc.Height          = 24;
	fontDesc.Width           = 0;
	fontDesc.Weight          = 0;
	fontDesc.MipLevels       = 1;
	fontDesc.Italic          = false;
	fontDesc.CharSet         = DEFAULT_CHARSET;
	fontDesc.OutputPrecision = OUT_DEFAULT_PRECIS;
	fontDesc.Quality         = DEFAULT_QUALITY;
	fontDesc.PitchAndFamily  = DEFAULT_PITCH | FF_DONTCARE;
	wcscpy_s(fontDesc.FaceName, L"Times New Roman");

	HR(D3DX10CreateFontIndirect(m_pDevice, &fontDesc, &m_pFont));

	return true;
}

void CD3D10RenderDevice::UnInit()
{
	if (m_pDevice)
	{
		m_pDevice->ClearState();
	}
	
	SAFE_RELEASE(m_pDevice);
	SAFE_RELEASE(m_pSwapChain);
	SAFE_RELEASE(m_pDepthStecilBuffer);
	SAFE_RELEASE(m_pRenderTargetView);
	SAFE_RELEASE(m_pDepthStencilView);
	SAFE_RELEASE(m_pFont);
}

void CD3D10RenderDevice::OnWindowResize(int nViewWidth, int nViewHeight)
{
	SAFE_RELEASE(m_pDepthStecilBuffer);
	SAFE_RELEASE(m_pRenderTargetView);
	SAFE_RELEASE(m_pDepthStencilView);

	m_nViewWidth  = nViewWidth;
	m_nViewHeight = nViewHeight;
	HR(m_pSwapChain->ResizeBuffers(1, nViewWidth, nViewHeight, DXGI_FORMAT_R8G8B8A8_UNORM, 0));

	ID3D10Texture2D* pBackBuffer;
	HR(m_pSwapChain->GetBuffer(0, __uuidof(ID3D10Texture2D), reinterpret_cast<void**>(&pBackBuffer)));
	HR(m_pDevice->CreateRenderTargetView(pBackBuffer, 0, &m_pRenderTargetView));
	SAFE_RELEASE(pBackBuffer);

	D3D10_TEXTURE2D_DESC  depthStencilDesc;
	depthStencilDesc.Width = nViewWidth;
	depthStencilDesc.Height = nViewHeight;
	depthStencilDesc.MipLevels = 1;
	depthStencilDesc.ArraySize = 1;
	depthStencilDesc.Format    = DXGI_FORMAT_D24_UNORM_S8_UINT;
	depthStencilDesc.SampleDesc.Count = 1;
	depthStencilDesc.SampleDesc.Quality = 0;
	depthStencilDesc.Usage     = D3D10_USAGE_DEFAULT;
	depthStencilDesc.BindFlags = D3D10_BIND_DEPTH_STENCIL;
	depthStencilDesc.CPUAccessFlags = 0;
	depthStencilDesc.MiscFlags = 0;

	HR(m_pDevice->CreateTexture2D(&depthStencilDesc, 0, &m_pDepthStecilBuffer));
	HR(m_pDevice->CreateDepthStencilView(m_pDepthStecilBuffer, 0, &m_pDepthStencilView));

	m_pDevice->OMSetRenderTargets(1, &m_pRenderTargetView, m_pDepthStencilView);

	D3D10_VIEWPORT  viewport;
	viewport.TopLeftX = 0;
	viewport.TopLeftY = 0;
	viewport.Width    = nViewWidth;
	viewport.Height   = nViewHeight;
	viewport.MinDepth = 0.0f;
	viewport.MaxDepth = 1.0f;

	m_pDevice->RSSetViewports(1, &viewport);
}

void CD3D10RenderDevice::OnResetDevice()
{

}

void CD3D10RenderDevice::ClearScene()
{
	m_pDevice->ClearRenderTargetView(m_pRenderTargetView, CLEAR_COLOR);
	m_pDevice->ClearDepthStencilView(m_pDepthStencilView, 
					D3D10_CLEAR_DEPTH | D3D10_CLEAR_STENCIL, 1.0f, 0);
}

void CD3D10RenderDevice::ResetViewport()
{
	D3D10_VIEWPORT  viewport;
	viewport.TopLeftX = 0;
	viewport.TopLeftY = 0;
	viewport.Width    = m_nViewWidth;
	viewport.Height   = m_nViewHeight;
	viewport.MinDepth = 0.0f;
	viewport.MaxDepth = 1.0f;

	m_pDevice->RSSetViewports(1, &viewport);
}

void CD3D10RenderDevice::ResetRenderTargets()
{
	m_pDevice->OMSetRenderTargets(1, &m_pRenderTargetView, m_pDepthStencilView);
}

void CD3D10RenderDevice::DrawIndexedPrimitiveList( 
	CVertexBuffer* pVertexBuffer, CIndexBuffer* pIndexBuffer, UINT32 dwVertexOffset, UINT32 dwIndexOffset)
{
	ID3D10Buffer* pD3DVB = pVertexBuffer->GetHandle();
	ID3D10Buffer* pD3DIB = pIndexBuffer->GetHandle();

	UINT32 dwStride   = pVertexBuffer->m_dwVertexSize;
	UINT32 dwIndexNum = pIndexBuffer->m_dwIndexCount;

	m_pDevice->IASetVertexBuffers(0, 1, &pD3DVB, &pVertexBuffer->m_dwVertexSize, &dwVertexOffset);
	m_pDevice->IASetIndexBuffer(pD3DIB, DXGI_FORMAT_R32_UINT, dwIndexOffset);
	m_pDevice->DrawIndexed(dwIndexNum, 0, 0);
}


void CD3D10RenderDevice::ShowText( const std::wstring& wstrText, RECT* pRect,  const D3DXCOLOR& color)
{	
	std::wstring text = wstrText;
	m_pFont->DrawText(0, text.c_str(), -1, pRect, DT_NOCLIP, color);	
}

void CD3D10RenderDevice::Present()
{
	m_pSwapChain->Present(0, 0);
}
